#include "pch.hpp"
#include "Window.hpp"
#include "WidgetImpl.hpp"
#include "WinException.hpp"
#include "Application.hpp"

using namespace WinUi;




Window::Window(Window* parent, const std::wstring& className, int2 pos, int2 size, int style)
	: Widget(parent, className, pos, size, style)
	, moved(m_moved)
	, resized(m_resized)
	, closing(m_closing)
	, activated(m_activated)
	, deactivated(m_deactivated)
{}
///////////////////////////////////////////////////////////////////////////////////////////////////

Window::~Window()
{}
///////////////////////////////////////////////////////////////////////////////////////////////////




void Window::add(Widget* widget)
{
	widget->setParent(this);
	m_widgets.push_back(widget);

	// TODO: Rearrange all widgets
}
///////////////////////////////////////////////////////////////////////////////////////////////////




bool Window::minimized() const
{
	return IsIconic(d->wnd) == TRUE;
}
///////////////////////////////////////////////////////////////////////////////////////////////////




void Window::showNormal()
{
	ShowWindow(d->wnd, SW_SHOWDEFAULT);
}
///////////////////////////////////////////////////////////////////////////////////////////////////

void Window::showMaximized()
{
	// ShowWindow does not indicate if the function succeeded
	ShowWindow(d->wnd, SW_MAXIMIZE);
}
///////////////////////////////////////////////////////////////////////////////////////////////////

void Window::showMinimized()
{
	WIN_API(CloseWindow(d->wnd));
}
///////////////////////////////////////////////////////////////////////////////////////////////////

void Window::toTop()
{
	WIN_API(BringWindowToTop(d->wnd));
}
///////////////////////////////////////////////////////////////////////////////////////////////////

void Window::toBottom()
{
	WIN_API(SetWindowPos(d->wnd, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOZORDER | SWP_NOREPOSITION | SWP_NOSIZE));
}
///////////////////////////////////////////////////////////////////////////////////////////////////




void Window::showCursor(bool show)
{
	ShowCursor(show ? TRUE : FALSE);
}
///////////////////////////////////////////////////////////////////////////////////////////////////

void Window::hideCursor(bool hide)
{
	ShowCursor(hide ? FALSE : TRUE);
}
///////////////////////////////////////////////////////////////////////////////////////////////////




LRESULT Window::msgProc(UINT msg, WPARAM wParam, LPARAM lParam)
{
	switch(msg)
	{
	case WM_ACTIVATEAPP:
		{
			// There is only one fucking MainWindow...
			// What a joke
			if(wParam == TRUE) Application::instance().activate();
			else               Application::instance().deactivate();
			return 0;
		}
		break;
	case WM_ACTIVATE:
		{
			if(LOWORD(wParam) == WA_ACTIVE) m_activated();
			else                            m_deactivated();
			return 0;
		}
	case WM_COMMAND:
		{
			// Delegate the actual notification to the child
			// Stupid windows design
			HWND hWnd = (HWND)lParam;
			Window* control = reinterpret_cast<Window*>(GetWindowLongPtr(hWnd, GWLP_USERDATA));
			if(control)
				return control->msgProc(msg, wParam, lParam);

			return 0;
		}
	case WM_PAINT:
		{
			RECT rect;
			WIN_API(GetClientRect(d->wnd, &rect));

			PAINTSTRUCT p;
			HDC hDc = BeginPaint(d->wnd, &p);
			WIN_API(hDc);
			WIN_API(FillRect(hDc, &rect, (HBRUSH)GetSysColor(COLOR_WINDOW)));
			WIN_API(EndPaint(d->wnd, &p));

			// Maybe the default routine wants to paint something as well
			//Widget::msgProc(msg, wParam, lParam);

			// Sent by an application when Windows or another application makes a request to paint
			// a portion of an application's window.

			return 0;
		}
	case WM_MOVE:
		{
			// The WM_MOVE message is sent after a window has been moved.
			int2 pos = Widget::pos();
			LRESULT ret = Widget::msgProc(msg, wParam, lParam);

			m_moved();

			return ret;
		}
	case WM_SIZE:
		{
			// When calling ID3D9Device::reset WM_SIZE is pretty likely to be received.
			// "Direct3D 9 applications can expect messages to be sent to them
			// during this call (for example, before this call is returned);
			// applications should take precautions not to call into Direct3D at this time."

			// The WM_SIZE message is sent to a window after its size has changed.
			int2 size = Widget::size();
			LRESULT ret = Widget::msgProc(msg, wParam, lParam);

			m_resized();

			return ret;
		}
	case WM_CLOSE:
		{
			// Ask for permission to close the window
			if(m_closing())
				return Widget::msgProc(msg, wParam, lParam);

			return 0;
		}
	default:
		{
			return Widget::msgProc(msg, wParam, lParam);
		}
	}
}
///////////////////////////////////////////////////////////////////////////////////////////////////
